package org.ghost.http.testkit.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.type.TypeReference;
import groovy.lang.Tuple2;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.ghost.http.testkit.dto.ConfigTestDataDTO;
import org.ghost.http.testkit.entity.ConfigHeader;
import org.ghost.http.testkit.entity.ConfigInterface;
import org.ghost.http.testkit.entity.ConfigSystemEnv;
import org.ghost.http.testkit.entity.ConfigTestData;
import org.ghost.http.testkit.mapper.ConfigTestDataMapper;
import org.ghost.http.testkit.service.IConfigHeaderService;
import org.ghost.http.testkit.service.IConfigInterfaceService;
import org.ghost.http.testkit.service.IConfigSystemEnvService;
import org.ghost.http.testkit.service.IConfigTestDataService;
import org.ghost.http.testkit.util.HttpClientHelper;
import org.ghost.http.testkit.util.HttpRequestBuilder;
import org.ghost.http.testkit.util.JacksonUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMethod;
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;

import java.lang.reflect.Type;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author author
 * @since 2018-05-02
 */
@Service
public class ConfigTestDataServiceImpl extends ServiceImpl<ConfigTestDataMapper, ConfigTestData> implements IConfigTestDataService {
    private final Logger logger = LoggerFactory.getLogger(ConfigTestDataServiceImpl.class);

    @Autowired
    private IConfigHeaderService configHeaderService;
    @Autowired
    private IConfigInterfaceService configInterfaceService;
    @Autowired
    private IConfigSystemEnvService configSystemEnvService;

    @Override
    public List<ConfigTestDataDTO> selectConfigTestData(Page page, ConfigTestDataDTO reqDTO) {
        return baseMapper.selectConfigTestData(page, reqDTO);
    }

    @Override
    public Tuple2<Boolean, String> test(Long interfaceId, Long envId) {
        if (interfaceId != null && envId != null) {
            //查询接口明细
            ConfigInterface configInterface = configInterfaceService.selectById(interfaceId);
            return this.test(configInterface, envId);
        }

        return new Tuple2<Boolean, String>(false, "interfaceId或envId参数错误");
    }

    @Override
    public Tuple2<Boolean, String> test(ConfigInterface configInterface, Long envId) {
        if (configInterface != null) {
            Long interfaceId = configInterface.getId();
            //查询测试用例
            Wrapper<ConfigTestData> configTestDataWrapper = new EntityWrapper<ConfigTestData>()
                    .eq("is_del", "0")
                    .eq("interface_id", interfaceId)
                    .eq("env_id", envId);
            List<ConfigTestData> configTestDataList = this.baseMapper.selectList(configTestDataWrapper);

            if (CollectionUtils.isNotEmpty(configTestDataList)) {
                //查询header信息
                Wrapper<ConfigHeader> configHeaderWrapper = new EntityWrapper<ConfigHeader>()
                        .eq("is_del", "0")
                        .eq("interface_id", interfaceId);
                List<ConfigHeader> configHeaderList = configHeaderService.selectList(configHeaderWrapper);

                //查询系统信息
                List<Long> envIdList = configTestDataList.stream().filter(Objects::nonNull).filter(it -> it.getEnvId() != null).map(ConfigTestData::getEnvId).collect(Collectors.toList());
                Wrapper<ConfigSystemEnv> configSystemEnvWrapper = new EntityWrapper<ConfigSystemEnv>()
                        .eq("is_del", "0")
                        .eq("sys_id", configInterface.getSysId())
                        .in("env_id", envIdList);
                List<ConfigSystemEnv> configSystemEnvList = configSystemEnvService.selectList(configSystemEnvWrapper);

                return test(configInterface, configHeaderList, configSystemEnvList, configTestDataList);
            } else {
                return new Tuple2<Boolean, String>(false, "ConfigTestData对象为空");
            }
        } else {
            return new Tuple2<Boolean, String>(false, "ConfigInterface对象为空");
        }
    }

    @Override
    public Map<Long, Tuple2<Boolean, String>> testAll(Long envId, Long sysId) {
        Map<Long, Tuple2<Boolean, String>> resultMap = null;
        if (envId != null && sysId != null) {
            //查询接口明细
            Wrapper<ConfigInterface> configInterfaceWrapper = new EntityWrapper<ConfigInterface>()
                    .eq("is_del", "0")
                    .eq("sys_id", sysId);
            List<ConfigInterface> configInterfaceList = configInterfaceService.selectList(configInterfaceWrapper);
            if (CollectionUtils.isNotEmpty(configInterfaceList)) {
                resultMap = configInterfaceList.parallelStream().map(it -> {
                    Tuple2<Boolean, String> rtn = this.test(it, envId);
                    return new Tuple2<Long, Tuple2<Boolean, String>>(it.getId(), rtn);
                }).collect(Collectors.toMap(Tuple2::getFirst, Tuple2::getSecond));
            }
        }

        return resultMap;
    }

    /**
     * 所有测试用例通过才算通过
     *
     * @param configInterface
     * @param configHeaderList
     * @param configSystemEnvList
     * @param configTestDataList
     * @return
     */
    Tuple2<Boolean, String> test(ConfigInterface configInterface, List<ConfigHeader> configHeaderList, List<ConfigSystemEnv> configSystemEnvList, List<ConfigTestData> configTestDataList) {
        for (ConfigTestData item : configTestDataList) {
            //查询host
            String host = configSystemEnvList.stream().filter(it -> Objects.equals(it.getEnvId(), item.getEnvId())).map(ConfigSystemEnv::getSysUrl).findFirst().orElse(null);
            if (StringUtils.isBlank(host)) {
                logger.error("*****ConfigTestDataServiceImpl.test查找系统host为空:" + item);
            } else {
                String url = MessageFormat.format("{0}/{1}", host, configInterface.getInterfaceUrl());
                Type expectType = ParameterizedTypeImpl.make(Map.class, new Type[]{String.class, Object.class}, HashMap.class);
                TypeReference<Map<String, Object>> expectTypeReference = new TypeReference<Map<String, Object>>() {
                    @Override
                    public Type getType() {
                        return expectType;
                    }
                };
                //预期输出结果
                Map<String, Object> expectResult = JacksonUtil.useDefaultMapper().fromJson(item.getOutputData(), expectTypeReference);

                HttpRequestBuilder httpRequestBuilder = new HttpRequestBuilder();
                if (configInterface.getRequestMethod() != null && Objects.equals(RequestMethod.GET.name(), configInterface.getRequestMethod().toUpperCase())) {
                    httpRequestBuilder.build(HttpMethod.GET, url);
                    if (StringUtils.isNotBlank(item.getInputData())) {
                        Type type = ParameterizedTypeImpl.make(Map.class, new Type[]{String.class, String.class}, HashMap.class);
                        TypeReference<Map<String, String>> typeReference = new TypeReference<Map<String, String>>() {
                            @Override
                            public Type getType() {
                                return type;
                            }
                        };
                        Map<String, String> paraMap = JacksonUtil.useDefaultMapper().fromJson(item.getInputData(), typeReference);
                        httpRequestBuilder.addUrlPara(paraMap);
                    }
                } else if (configInterface.getRequestMethod() != null && Objects.equals(RequestMethod.POST.name(), configInterface.getRequestMethod().toUpperCase())) {
                    httpRequestBuilder.build(HttpMethod.POST, url);
                    if (StringUtils.isNotBlank(item.getInputData())) {
                        httpRequestBuilder.addBody(JacksonUtil.useDefaultMapper().fromJson(item.getInputData(), Map.class));
                    }
                } else if (configInterface.getRequestMethod() != null && Objects.equals(RequestMethod.PUT.name(), configInterface.getRequestMethod().toUpperCase())) {
                    httpRequestBuilder.build(HttpMethod.PUT, url);
                    if (StringUtils.isNotBlank(item.getInputData())) {
                        httpRequestBuilder.addBody(JacksonUtil.useDefaultMapper().fromJson(item.getInputData(), Map.class));
                    }
                }
                if (CollectionUtils.isNotEmpty(configHeaderList)) {
                    configHeaderList.forEach(it -> {
                        httpRequestBuilder.addHeader(it.getName(), it.getValue());
                    });
                }
                //实际输出结果
                Map<String, Object> resultMap = HttpClientHelper.invoke(httpRequestBuilder, Map.class, null, String.class, Object.class);
                boolean suc = equals(expectResult, resultMap);
                if (!suc) {
                    return new Tuple2<Boolean, String>(false, "返回值不匹配");
                }
            }
        }

        return new Tuple2<Boolean, String>(true, null);
    }

    private boolean equals(Object expect, Object actual) {
        if (expect == null && actual == null) {
            return true;
        } else if (expect != null && actual != null && expect instanceof Map && actual instanceof Map) {
            Map<String, Object> expectMap = (Map<String, Object>) expect;
            Map<String, Object> actualMap = (Map<String, Object>) actual;
            if (expectMap.size() == actualMap.size()) {
                for (Map.Entry<String, Object> entry : expectMap.entrySet()) {
                    Object expectValue = entry.getValue();
                    Object actualValue = MapUtils.getObject(actualMap, entry.getKey(), null);
                    boolean suc = equals(expectValue, actualValue);
                    if (!suc) {
                        return false;
                    }
                }
                return true;
            } else {
                return false;
            }
        } else if (expect != null && actual != null && expect instanceof List && actual instanceof List) {
            List<Object> expectList = (List<Object>) expect;
            List<Object> actualList = (List<Object>) actual;
            if (expectList.size() == actualList.size()) {
                int size = expectList.size();
                for (int i = 0; i < size; i++) {
                    boolean suc = equals(expectList.get(i), actualList.get(i));
                    if (!suc) {
                        return false;
                    }
                }
                return true;
            } else {
                return false;
            }
        } else {
            return Objects.equals(expect, actual);
        }
    }
}
